/**contiene:
 * 	\li le strutture dati che rappresentano una matrice di g
 * 	\li le funzioni per gestire tale struttura dati in maniera semplice e veloce
 */
#ifndef GMATRIX_H_
#define GMATRIX_H_

#include <stdio.h>
#include "edgeID.h"

/**se una cella del campo matrix assume questo valore allora l'arco associato a tale cella non e' soddisfatto da nessun camion*/
#define NOT_GATHERED -1

/**rappresenta un matrice di interi. Ogni cella di tale matrice rappresenta il camion che ha soddisfato, in un qualunque momento
 * dell'algoritmo l'arco (i;j) con i il numero di riga della matrice e j il numero di colonna della matrice.
 * In caso il numero contenuto sia NOT_GATHERED, l'arco non è stato soddisfatto da nessun camion  */
typedef struct GMatrix{
	/**la matrice delle g*/
	int** matrix;
	/**un puntatore ad una cella di memoria in cui è contenuto il numero di nodi del grafo*/
	int* N;
} GMatrix;

/**un puntatore ad una struttura GMatrix*/
typedef GMatrix* PGMatrix;

/**costruisce una nuova matrice G
 *
 * \pre
 * 	\li il puntatore _N non deve essere NULL
 * \post
 *  \li un puntatore a GMatrix o NULL in caso di memoria non sufficiente
 *
 * @param _N un puntatore ad una cella in cui ci sian il numero di nodi del grafo
 * @param _basevalue il valore da inserire in ogni cella della matrice
 * @return un riferimento alla matrice creata.
 */
PGMatrix initGMatrix(int* _N, int _basevalue);

/**libera la memoria dalla matrice.
 *
 * \pre
 *  \li matrix non deve essere NULL
 * \post tutta l'area in memoria occupata da matrix e' liberata. Non viene deallocata la cella puntata da N
 *
 * @param matrix un riferimento alla matrice da deallocare
 */
void freeGMatrix(PGMatrix matrix);

/**Genera una nuova istanza di PGMatrix uguale tutto per tutto all'originale. La tabella mostra cosa viene copiato fisicamente
 * e cosa invece viene semplicemente copiato per indirizzo
 *
 *	<table>
 *		<tr>
 *		 <th>Campo</th>
 *		 <th>Copia per...</th>
 *		</tr>
 *		<tr>
 *		 <td>matrix</td>
 *		 <td>copia fisica</td>
 *		</tr>
 *		<tr>
 *		 <td>N</td>
 *		 <td>copia per indirizzo</td>
 *		</tr>
 *	</table>
 *
 *	\pre
 *	 \li matrix non NULL;
 *	\post
 *	 \li una nuova martrice e' immagazzinata in memoria. <b>Deallocare</b> qualora non serva piu';
 *
 * @param matrix la matrice originale da copiare
 * @return un puntatore ad una nupva istanza di matrix (da deallocare manualmente qualora non serva piu')
 */
PGMatrix cloneGMatrix(PGMatrix matrix);

/**stampa la matrice matrix
 *
 * @param f un riferimento al file su cui scrivere la stampa
 * @param matrix un riferimento alla matrix la matrice da stampare
 */
void printGMatrix(FILE* f, PGMatrix matrix);

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~QUERYING~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/** informa sul proprietario della raccolta di un arco.
 * \pre
 *	\li ps non NULL
 *	\li id non NULL
 *	\li id deve avere i<j
 *
 * @param un riferimento alla matrice
 * @param pe puntatore all'edge interessato
 * @return l'identificativo del veicolo che raccoglie l'arco, oppure NOGATHERED se non è soddisfatto da alcun veicolo
 */
int whoGathersEdge(PGMatrix pgm, PedgeID pe);

/** determina se l'arco e' raccolto o meno
 *
 * \pre
 * 	\li ps non deve essere NULL
 * 	\li id non deve essere NULL
 * 	\li id deve avere i<j
 *
 * @param un riferimento alla matrice
 * @param pe puntatore all'arco interessato
 * @return TRUE se l'arco e' raccolto da un camion, FALSE altrimenti
 */
bool isEdgeGathered(PGMatrix pgm, PedgeID pe);

/**indica se un camion raccoglie un particolare arco
 * \pre
 * 	\li p_gMatrix non deve essere NULL
 * 	\li e non deve essere NULL
 * 	\li e deve avere i<j (arco validato)
 * 	\li k>=0 e k<=K
 *
 * @param p_gMatrix un riferimento alla matrice
 * @param p_edgeID puntatore all'arco da considerare
 * @param k il camion da considerare
 * @return TRUE se il camion soddisfa l'arco, FALSE altrimenti
 */
bool amIGatheringEdge(PGMatrix p_gMatrix, PedgeID p_edgeID, int k);

/** rilascia un arco da parte di un veicolo, solo se egli lo raccoglieva per davvero.
 * \pre
 * 	\li p_gMatrix non deve essere NULL
 * 	\li e non deve essere NULL
 * 	\li e deve avere i<j
 * 	\li k>=0 e k<=K
 *
 * @param p_gMatrix un riferimento alla matrice
 * @param p_edgeID puntatore all'arco da considerare
 * @param k il camion da considerare
 * @return TRUE se il camion soddisfava l'arco e pertanto ho rimosso, FALSE altrimenti */
bool releaseIfImGatheringEdge(PGMatrix p_gMatrix, PedgeID p_edgeID, int k);

/**tenta di raccogliere il profitto dato dall'arco: l'azione fallisce se l'arco era gia' stato raccolto da un altro
 * camion precedentemente. <b>NON</b> vengono aggiornate le altre strutture di Solution, quindi si sconsiglia di usare questa funzione.
 * Per una funzione che lascia senza conflitti le strutture uasre addEdgeIDInSolution() o removeEdgeIDInSolution().
 *
 * \pre
 * 	\li ps non NULL
 * 	\li e non NULL
 * 	\li e ha i<j
 * 	\li k>=0 e k<=K
 *
 * \post
 * 	\li l'arco e viene soddisfatto. O da un camion precedente a questo oppure dal camion stesso
 *
 * @param un riferimento alla matrice
 * @param pe puntatore all'arco da tentare di soddisfare
 * @param k il camion che deve tentare di soddisfare e
 * @return TRUE se l'arco non era gia' stato raccolto da altri camion, FALSE altrimenti
 */
bool tryToGatherEdge(PGMatrix pgm, PedgeID pe, int k);

/**raccoglie l'arco specificato <b>senza</b> effettuare alcun controllo sul fatto che l'arco fosse gia' stato
 * soddisfatto. <b>NON</b> vengono aggiornate le altre strutture di Solution, quindi si sconsiglia di usare questa funzione.
 * Per una funzione che lascia senza conflitti le strutture uasre addEdgeIDInSolution() o removeEdgeIDInSolution().
 *
 * \pre
 *  \li ps non NULL
 *  \li e non NULL
 *  \li e ha i<j
 *  \li k>=0 e k<=K
 * \post
 *  \li l'arco e viene soddisfatto dal camion k
 *  \li la matrice di g della soluzione ps ha nelle coordinate specificate da e il valore k
 *
 * @param un riferimento alla matrice
 * @param pe puntatore all'arco da soddisfare
 * @param k il camion che soddisfa la domanda
 */
void gatherEdge(PGMatrix pgm, PedgeID pe, int k);

/** Rilascia il riferimento alla raccolta dell'arco. */
void releaseGatherEdge(PGMatrix pgm, PedgeID pe);

#endif /* GMATRIX_H_ */
